import http from 'wechat-http'

let app = null

http.baseURL = 'https://live-api.itheima.net'

http.intercept.request = function (config) {
  if (!app) app = getApp()

  if (!!app.token) {
    if (config.header) {
      config.header.Authorization = `Bearer ${app.token}`
      // 这种方式会覆盖掉已有的header，不可取
      // config.header = { Authorization: `Bearer ${app.token}` }
    } else {
      config.header = { Authorization: `Bearer ${app.token}` }
    }
  }

  // 一定要return
  return config
}

http.intercept.response = function (res) {
  if (String(res.statusCode).startsWith('2')) {
    // 请求成功了，业务不一定成功
    // res =>  { data: { code, data, message } }
    // 统一在这里弹出错误信息
    if (res.data.code !== 10000) {
      wx.utils.toast(res.data.message)
      return Promise.reject(res)
    }
    // 直接返回一个普通的数据，或者成功的Promise，则当前的Promise状态会变成成功
    return res.data // ==> Promise.resolve(res.data)
  } else if (res.statusCode === 401) {
    // 响应状态码为401，说明token失效了
    // 发送刷新token的请求，更新token了

    // 如果返回一个promise，后面的逻辑要受这个promise的影响
    return wx.http.refreshToken().then(() => wx.http(res.config))
    // .catch(() => wx.utils.redirectToLogin())

    // // 不要使用wx.http，因为刷新token请求不需要经过拦截器
    // // 必须要返回一个Promise，因为wx.request不支持Promise
    // return new Promise((resolve, reject) => {
    //   wx.request({
    //     method: 'post',
    //     url: wx.http.baseURL + '/refreshToken',
    //     header: { Authorization: `Bearer ${app.refreshToken}` },
    //     success(res2) {
    //       if (String(res2.statusCode).startsWith('2')) {
    //         // 成功后，拿到最新的token，替换旧的token
    //         const { token, refreshToken } = res2.data.data
    //         app.setToken(token)
    //         app.setRefreshToken(refreshToken)
    //         // 发送上一次失败的请求
    //         // 怎么知道上一次发的是啥请求呢？ 可以通过响应拦截器中的数据中的config获取
    //         // 这里需要使用wx.http发，因为需要走拦截器逻辑
    //         resolve(wx.http(res.config))
    //         // Promise语法逻辑：如果调用resolve时，传递的又是一个Promise，那么resolve会受这个Promise的影响
    //       } else {
    //         wx.utils.redirectToLogin()
    //         reject(res2)
    //       }
    //     },
    //     fail(err) {
    //       wx.utils.redirectToLogin()
    //       reject(err)
    //     },
    //   })
    // })
  } else {
    // 请求都失败了
    wx.utils.toast('服务器繁忙，请稍后重试')
    return Promise.reject(res)
  }
}

// 作业1：
// 需求：
//   1. 实现上传头像
//   2. 返回Promise
http.uploadAvatar = function (filePath) {
  // show your code...
  return new Promise((resolve, reject) => {
    if (!app) app = getApp()
    wx.uploadFile({
      url: wx.http.baseURL + '/upload',
      filePath,
      name: 'file',
      formData: {
        type: 'avatar', // 上传文件有很多，指定这个表示当前上传的用户头像
      },
      header: {
        Authorization: `Bearer ${app.token}`,
      },
      success: (res) => {
        if (String(res.statusCode).startsWith('2')) {
          const data = JSON.parse(res.data)
          if (data.code === 10000) {
            resolve(data.data.url)
          } else {
            wx.utils.toast(data.message)
            reject(res)
          }
        } else if (res.statusCode === 401) {
          // token过期了

          // const p = wx.http
          //   .refreshToken()
          //   .then(() => wx.http.uploadAvatar(filePath))
          //   .catch(() => wx.utils.redirectToLogin())
          // resolve(p)

          resolve(wx.http.refreshToken().then(() => wx.http.uploadAvatar(filePath)))
        } else {
          wx.utils.toast('上传头像失败，请重试')
          reject(res)
        }
      },
      fail(err) {
        wx.utils.toast('上传头像失败，请重试')
        reject(err)
      },
    })
  })
}

// 作业2：
// 需求：
//   1. 实现普通文件上传
//   2. 返回Promise

/**
 * 实现普通文件上传
 * @param {*} filePath 临时文件路径
 * @param {*} isShowToast 是否显示错误提示
 * @param {*} isAutoHideLoading 是否自动关闭loading
 * @returns 返回Promise
 */
http.uploadFile = function (filePath, isShowToast = true, isAutoHideLoading = true) {
  // show your code...
  return new Promise((resolve, reject) => {
    wx.showLoading({
      title: '上传中...',
    })

    // 执行器函数，同步执行
    if (!app) app = getApp()
    ;(() => {
      // 搞一个立即执行函数，用来封闭这段逻辑中定义的变量，避免和外部的变量名冲突
      // 注意：立即执行函数前最好加个分号，否则有可能会导致逻辑错乱 ==> fn()  (() => {})()
      const arr = filePath.split('.')
      const suffix = arr[arr.length - 1].toLowerCase()
      arr.splice(arr.length - 1, 1, suffix)
      filePath = arr.join('.')
    })()

    wx.uploadFile({
      filePath,
      name: 'file',
      url: wx.http.baseURL + '/upload',
      header: {
        Authorization: `Bearer ${app.token}`,
      },
      success: (res) => {
        if (String(res.statusCode).startsWith('2')) {
          const data = JSON.parse(res.data)
          if (data.code === 10000) {
            resolve(data)
          } else {
            if (isShowToast) wx.utils.toast(data.message)
            reject(res)
          }
        } else if (res.statusCode === 401) {
          resolve(wx.http.refreshToken().then(() => http.uploadFile(filePath)))
        } else {
          if (isShowToast) wx.utils.toast('上传失败，请重试')
          reject(res)
        }
      },
      fail: (err) => {
        if (isShowToast) wx.utils.toast('上传失败，请重试')
        reject(err)
      },
      complete() {
        if (isAutoHideLoading) {
          wx.hideLoading()
        }
      },
    })
  })
}

// 作业3：
// 需求：
//   1. 实现刷新token
//   2. 返回Promise
http.refreshToken = function () {
  // show your code...
  return new Promise((resolve, reject) => {
    if (!app) app = getApp()
    wx.request({
      method: 'post',
      url: wx.http.baseURL + '/refreshToken',
      header: { Authorization: `Bearer ${app.refreshToken}` },
      success(res) {
        // 状态码有两种：HTTP状态码、业务状态码

        // 请求服务器成功
        if (String(res.statusCode).startsWith('2')) {
          // 业务成功
          if (res.data.code === 10000) {
            // 成功后，拿到最新的token，替换旧的token
            const { token, refreshToken } = res.data.data
            app.setToken(token)
            app.setRefreshToken(refreshToken)
            resolve({ token, refreshToken })
          } else {
            reject(res)
            wx.utils.redirectToLogin()
          }
        } else {
          reject(res)
          wx.utils.redirectToLogin()
        }
      },
      fail(err) {
        reject(err)
        wx.utils.redirectToLogin()
      },
    })
  })
}

export default http

wx.http = http
